package com.glsc.ngateway.oaflow.service;

import cn.hutool.core.collection.CollectionUtil;
import com.glsc.ngateway.common.api.oaflow.dto.SyncPlatformFlowCommonDto;
import com.glsc.ngateway.common.api.common.enums.ExceptionConstant;
import com.glsc.ngateway.common.api.common.enums.GatewayConstant;
import com.glsc.ngateway.common.base.domain.mysql.gateway.oaflow.TOaFlowMetaTable;
import com.glsc.ngateway.common.base.domain.mysql.gateway.oaflow.TOaFlowRelativeMetaTable;
import com.glsc.ngateway.common.base.repo.mysql.gateway.oaflow.TOaFlowMetaTableRepository;
import com.glsc.ngateway.common.base.repo.mysql.gateway.oaflow.TOaFlowRelativeMetaTableRepository;
import com.glsc.ngateway.oaflow.exception.BusinessException;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class MetaFlowService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final static String META_FLOW_TABLE_FIELD_NON_REQUIRED = "0";
    private final static String META_FLOW_TABLE_FIELD_REQUIRED = "1";

    @Autowired
    private TOaFlowMetaTableRepository metaRepo;


    @Autowired
    private TOaFlowRelativeMetaTableRepository relativeRepo;


    //取得必填字段，字段名称为转义后的
    public Set<String> getMandatoryFields(String workFlowId, String detailIndex) {
        return metaRepo.getMandatoryFields(workFlowId, detailIndex);
    }

    //取得必填的明细字段，字段名称为转义后的
    public Map<String, Set<String>> getMandatoryDetails(String workFlowId) {
        int detailCount = Integer.parseInt(metaRepo.getMandatoryDetailFields(workFlowId));
        Map<String, Set<String>> map = new HashMap<>();
        for (int i = 1; i <= detailCount; i++) {
            String detailIndex = String.valueOf(i);
            map.put(detailIndex, metaRepo.getMandatoryFields(workFlowId, detailIndex));
        }
        return map;
    }

    public String checkFLowParams(Map<String, Object> dataOb, Set<String> fieldSet, Map<String, Set<String>> detailSets) {
        Set<String> set = new HashSet<>();
        //检查datamap是否包含主必填字段
        for (String field : fieldSet) {
            if (!dataOb.containsKey(field)) {
                set.add(field);
            }
        }
        //检查datamap中的明细是否在明细必填字段中
        List<Map<String, Object>> list = (List<Map<String, Object>>) dataOb.get("detailList");
        if (list != null) {
            if (detailSets != null && detailSets.size() > 0) {
                checkDetailParams(list, detailSets, set);
            }
        }

        if (set.size() > 0) {
            return set.toString();
        } else {
            return GatewayConstant.PARAMS_VERIFICATION;
        }

    }

    public Set<String> checkDetailParams(List<Map<String, Object>> list, Map<String, Set<String>> detailSets, Set<String> set) {
        boolean[] detailUsed = new boolean[detailSets.size()];
        for (Map<String, Object> detailMap : list) {
            String detailIndex = detailMap.get("detailIndex").toString();
            detailUsed[Integer.parseInt(detailIndex) - 1] = true;
            Set<String> dset = detailSets.get(detailIndex);
            for (String detailField : dset) {
                if (!detailMap.containsKey(detailField)) {
                    set.add(detailField);
                }
            }
        }
        for (int i = 0; i < detailSets.size(); i++) {
            if (!detailUsed[i]) set.addAll(detailSets.get(String.valueOf(i + 1)));
        }
        return set;
    }

    public List<TOaFlowMetaTable> getFlowMetaDataList(String workFlowId) {
        return metaRepo.getFlowMetaDataList(workFlowId);
    }


    //    public TOaFlowRelativeMetaTable getFlowTableRelative(String workFlowId) {
//        return relativeRepo.getFlowTableRelative(workFlowId);
//    }
//
    public List<TOaFlowRelativeMetaTable> getFlowTableRelativeList(String workFlowId) {
        return relativeRepo.findByWorkFlowId(workFlowId);
    }
//
//
//    public List<TOaFlowRelativeMetaTable> getFlowTableRelativeListByAppendixType(String workFlowId, String appendixType) {
//
//        return relativeRepo.getFlowTableRelativeListByAppendixType(workFlowId, appendixType);
//    }


    /**
     * 将数据根据配置项转义
     */
    public Map<String, Object> exchangeFields(SyncPlatformFlowCommonDto.GatewayFlowDataDto<?> formData, List<TOaFlowMetaTable> metaList) {
        if (CollectionUtil.isEmpty(metaList)) {
            logger.error(String.format("创建流程失败：未找到meta配置项- flowId: %s", formData.getWorkflowId()));
            throw new BusinessException(ExceptionConstant.BussinessException, String.format("创建流程失败：未找到meta配置项- flowId: %s", formData.getWorkflowId()));
        }
        Map<String, String> data = (Map<String, String>) formData.getFormData();
        //边组装边校验必填字段
        return metaList.stream()
                .collect(Collectors.toMap(TOaFlowMetaTable::getFlowFieldName, m -> {
//                    try {
                        //反射获取对象属性值
//                        Field field = formData.getFormData().getClass().getDeclaredField(m.getInterfaceFieldName());
//                        field.setAccessible(true);
//                        return field.get(formData.getFormData());
                        return data.getOrDefault(m.getInterfaceFieldName(), Strings.EMPTY);
//                    } catch (NoSuchFieldException | IllegalAccessException e) {
//                        if (META_FLOW_TABLE_FIELD_REQUIRED.equals(m.getIsRequired())) {
//                            logger.error(String.format("创建流程失败：反射生成data异常- flowId: %s, 字段 %s -> 字段 %s, \r\n%s", formData.getWorkFlowId(), m.getInterfaceFieldName(), m.getFlowFieldName(), e.getMessage()));
//                            throw new BusinessException(ExceptionConstant.BussinessException, String.format("创建流程失败：反射生成data异常- flowId: %s, 字段 %s -> 字段 %s", formData.getWorkFlowId(), m.getInterfaceFieldName(), m.getFlowFieldName()));
//                        } else {
//                            return Strings.EMPTY;
//                        }
//                    }
                }));
    }
}
